'''
Created on Jan 29, 2010

@author: Andrzej
'''
import os
import serial
import telnetlib
import time
import re

from PyDaq.Utils.Debug import dbg

PROMPT_FOUND = 1
PROMPT_NOT_FOUND = 0
PORT_OPEN = 1
PORT_CLOSED = 0
PORT_ERROR = -1

TIMEOUT = 2

class SimInterface():
    '''
    class SimInterface - class used to simulate AVR device attached to the host
    '''
    host = ''
    port = 0
    debug = 0
    _interface_open = 0
    _input_buffer   = []
    _output_buffer  = []
    _re_prompt = re.compile('(cmd>)')
    
    def __init__(self, host=0, port=0):
        self.host = host
        self.port = port       
        self.open()
    
    def __del__(self):
        dbg(self, 1, "Deleting Interface")
        pass
    
    def __unicode__(self):
        return "SimInterface(%s:%d)" % (self.host, self.port)
   
    def isOpen(self):
        if self._interface_open:
            return PORT_CLOSED
        else:
            return PORT_CLOSED            
        
    def GetPrompt(self):
        dbg(self, 1, "def GetPrompt(self):")
        return PROMPT_FOUND
            
    def open(self):
        self._interface_open = 1
        return PORT_OPEN
    
    def close(self):
        self._interface_open = 0
        
    def send(self, cmd):
        msg = 'def send(self, cmd="%s"):' % cmd
        dbg(self, 1, msg)       
       
        
    def read(self, expected_text=''):
        response = "cmd>"  
        dbg(self, 2, "Read   : " + response)
        return response

class TelnetInterface():
    '''
    classdocs
    '''
    host = ''
    port = 0
    debug = 0;
    _re_prompt = re.compile('(cmd>)')
    Tel = telnetlib.Telnet();
    Tel.timeout = 2

    def __init__(self, host, port):
        self.host = host
        self.port = port       
        self.open()
    
    def __del__(self):
        dbg(self, 1, "Deleting Interface")
        if not(self.Tel.sock):
            dbg(self, 2, "no open sockets")
        else:
            self.Tel.close()
    
    def __unicode__(self):
        return "TelnetInterface(%s:%d)" % (self.host, self.port)
   
    def isOpen(self):
        if self.Tel.sock == None:
            return PORT_CLOSED
        else:
            if self.Tel.sock == 0:
                return PORT_CLOSED
            else:
                return PORT_OPEN
        
    def GetPrompt(self):
        dbg(self, 1, "def GetPrompt(self):")
        port_status = self.open()
        if port_status == PORT_OPEN:        
            try:
                self.Tel.write('\n')
                prompt_str = self.Tel.read_until('cmd>', timeout=0.2)
                if len(prompt_str) > 0:
                    dbg(self, 2, "PROMPT_FOUND:")
                    dbg(self, 2, prompt_str)
                    return PROMPT_FOUND
                else:
                    dbg(self, 2, "PROMPT_NOT_FOUND")
                    return PORT_ERROR
            except:
                dbg(self, 1, 'Exception in "def GetPrompt(self):"')
                dbg(self, 2, "PROMPT_NOT_FOUND")
                return PORT_ERROR
        elif port_status == PORT_ERROR:
            dbg(self, 2, "PORT_ERROR")
            return PORT_ERROR                   
        else:
            dbg(self, 2, "PROMPT_NOT_FOUND")
            return PORT_ERROR
            
    def open(self):
        if self.isOpen():
            return PORT_OPEN
        else:   
            #dbg(self, 1, "Open Telnet:" + self.host) 
            try:
                self.Tel.open(self.host, self.port, timeout=1)
                return PORT_OPEN
            except:
                print "Error occured while oppening Telnet Interface"
                return PORT_ERROR
    
    def close(self):
        if not self.isOpen():
            return
        else:   
            dbg(self, 1, "Closing Telnet:" + self.host) 
            try:
                self.Tel.close()
            except:
                print "Error occured"
        
    def send(self, cmd):
        msg = 'def send(self, cmd="%s"):' % cmd
        dbg(self, 1, msg)
        
        if len(cmd) == 0:
            msg = 'cannot send empty command'
            dbg(self, 1, msg)
            return
        
        if (cmd[-1] == "\n"):
            pass            
        else:
            msg = "adding CR to cmd"
            dbg(self, 2, msg)
            cmd += "\n"
          
        if self.open() == PORT_OPEN:            
            self.Tel.write(cmd)
            time.sleep(0.01)
        else:
            msg = "Serial port is not open"
            dbg(self, 2, msg)
        pass
        
    def read(self, expected_text=''):
        if not(self.Tel.sock):
            print "Cannot read, no active connection"
            response = ''
        else:
            try:
                if len(expected_text) > 0:
                    response = self.Tel.read_until(expected_text, timeout=TIMEOUT)
                else:
                    response = self.Tel.read_very_eager()
            except(EOFError):
                response = ''
        dbg(self, 2, "Read   : " + response)
        return response

class SerialInterface():
   
    host = 'COM'
    port = 0
    debug = 0
    _re_prompt = re.compile('(cmd>)')
    Ser = [];
    
    
    def __init__(self, port=1):
        
        #self.port = port        
        if os.name == 'nt':
            port = port - 1
        
        self.Ser = serial.Serial(port=port, baudrate=115200, timeout=1)        
                
    def __del__(self):
        dbg(self, 1, "def __del__(self):")
        self.Ser.close()
        
    def __unicode__(self):
        return "SerialInterface"
            
    def isOpen(self):
        return self.Ser.isOpen()
    
    def GetPrompt(self):
        dbg(self, 1, "def GetPrompt(self):")
        port_status = self.open()
        if port_status == PORT_OPEN:
            try:
                self.Ser.write('\n')
                #prompt_str = self.Tel.read_until('cmd>', timeout=0.1)
                time.sleep(0.05)
                prompt_str = self.Ser.read(self.Ser.inWaiting())
                if prompt_str.find('cmd>') > 0:
                    return PROMPT_FOUND
                else:
                    return PROMPT_NOT_FOUND
            except:
                dbg(self, 1, 'Error in def GetPrompt(self):')
                return PORT_ERROR
        elif port_status == PORT_ERROR:
            return PORT_ERROR                   
        else:
            return PROMPT_NOT_FOUND
    
    def open(self):
        dbg(self, 1, "def open(self):")
        if not(self.Ser.isOpen()):            
            try:
                self.Ser.open()
                dbg(self, 2, "Port %d is now open" % self.port)
                return PORT_OPEN
            except serial.SerialException:
                dbg(self, 0, "SerialException Cannot open port: %d " % self.port)
                return PORT_ERROR
            except:
                dbg(self, 0, "OtherException Cannot open port: %d" % self.port)
                return PORT_ERROR
        else:
            dbg(self, 2, "Port %d is already open" % self.port)
            return PORT_OPEN        
    
    def close(self):
        dbg(self, 1, "def close(self)")
        if self.Ser.isOpen():
            dbg(self, 3, "Closing port: %d " % self.port)
            self.Ser.close()
        else:
            dbg(self, 3, "Port: %d is already closed" % self.port)
            pass
       
    def send(self, cmd):
        msg = 'def send(self, cmd="%s"):' % cmd
        dbg(self, 1, msg)
        
        if len(cmd) == 0:
            msg = 'cannot send empty command'
            dbg(self, 1, msg)
            return
        
        if (cmd[-1] == "\n"):
            pass            
        else:
            msg = "adding CR to cmd"
            dbg(self, 2, msg)
            cmd += "\n"
          
        if self.open() == PORT_OPEN:            
            self.Ser.write(cmd)
            time.sleep(0.01)
        else:
            msg = "Serial port is not open"
            dbg(self, 2, msg)
        pass
    
    def read(self, expected_text=''):
        #dbg(self, 1, "def read(self):")
        if self.open() == PORT_OPEN:
            try:                
                to = time.clock()
                response = ''
                while time.clock() - to < TIMEOUT:
                    n = self.Ser.inWaiting()
                    if n > 0:
                        response += self.Ser.read(n)
                    if expected_text in response:
                        return response
                return response
            except:
                return ''
        else:
            dbg(self, 2, "Could not open the port")
            return ''
    
if __name__ == '__main__':
    print "================================"
    print "AvrShell module test function"

    
    
    
